package com.liuwa.framework.manager;

import com.liuwa.common.config.GlobalProperties;
import com.liuwa.common.constant.Constants;
import com.liuwa.common.exception.ServiceException;
import com.liuwa.common.exception.SimpleException;
import com.liuwa.common.utils.LockUtils;
import com.liuwa.common.utils.StringUtils;
import com.liuwa.common.utils.Threads;

import java.util.concurrent.TimeUnit;

/**
 * 验证码管理
 * @author rubekid
 *
 * 2017年10月13日 下午5:03:31
 */
public class CaptchaManager {


	/**
	 * 注册
	 */
	public static final String TYPE_REGISTER = "REGISTER";

	/**
	 * 登录
	 */
	public static final String TYPE_LOGIN = "LOGIN";

	/**
	 * 绑定
	 */
	public static final String TYPE_BIND = "BIND";

	/**
	 * 修改手机号
	 */
	public static final String TYPE_CHANGE_PHONE = "MODIFY";

	/**
	 * 重置密码
	 */
	public static final String TYPE_RESET_PASSWORD = "RESET_PWD";


	/**
	 * 缓存key
	 */
	public static final String CACHE_KEY = "captcha:%s:%s";


	/**
	 * 缓存key
	 */
	public static final String LOCK_KEY = "captcha:lock:";

	/**
	 * 验证码错误统计过期时间
	 */
	public static final Integer CODE_EXPIRATION_TIMEOUT = 300;

	/**
	 * 有效时间
	 */
	private static final Integer EXPIRE_TIME = GlobalProperties.getPropertyForInteger("captcha.expire_time", "1800");

	/**
	 * 短信验证码 - 测试值
	 */
	public static final String SMS_CODE_TEST_VALUE = GlobalProperties.getProperty("sms.code.test.value", "");


	/**
	 * 生成验证码
	 * @param type
	 * @param phone
	 * @return
	 */
	public static String generate(String type, String phone){
		String lockKey = LOCK_KEY + phone + ":" + type;
		if(LockUtils.lock(lockKey)){

			String code = StringUtils.getRandomNumString(4);
			RedisManager.set(key(type, phone), code, EXPIRE_TIME);
			LockUtils.expire(lockKey, 60);
			return code;

		}
		throw new ServiceException("请勿频繁发送验证码");


	}

	/**
	 * 验证码校验
	 * @param type
	 * @param phone
	 * @param code
	 * @return
	 */
	public static void verify(String type, String phone, String code){
		if(!simpleVerify(type, phone, code)){
			throw new SimpleException("验证码错误，请重试");
		}
	}

	/**
	 * 简单校验
	 * @param type
	 * @param phone
	 * @param code
	 * @return
	 */
	public static boolean simpleVerify(String type, String phone, String code){
		if(StringUtils.isEmpty(code)){
			return false;
		}

		String cacheKey = key(type, phone);
		String lastCode = RedisManager.get(cacheKey, "");
		if(!code.equals(lastCode) && !code.equals(SMS_CODE_TEST_VALUE)){

			// 设置重复查询次数，避免被恶意破解
			String countDownKey = cacheKey + ":error";
			long times = RedisManager.incrBy(countDownKey, 1);
			if(times == 1){
				RedisManager.expire(countDownKey, CODE_EXPIRATION_TIMEOUT);
			}
			else if(times >= 10){
				RedisManager.remove(countDownKey);
				RedisManager.remove(cacheKey);
			}

			return false;
		}
		return true;
	}

	/**
	 * 获取最后有效验证码
	 * @param type
	 * @param phone
	 * @return
	 */
	public static String getLastCode(String type, String phone){
		return RedisManager.get(key(type, phone), "");
	}

	/**
	 * key组装
	 * @param type
	 * @param phone
	 * @return
	 */
	private static String key(String type, String phone){
		return String.format(CACHE_KEY, type, phone);
	}
}